import { InboxOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
import type { UploadFile, UploadProps } from 'antd';
import { Button, Upload, message } from 'antd';
import { MessageInstance } from 'antd/es/message/interface';
import { UploadListType } from 'antd/es/upload/interface';
import {
  CSSProperties,
  ReactNode,
  isValidElement,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { CardItem, InfoItem, ListItemType } from './ItemRender';
import { useStyle } from './style';
import { fileToBase64 } from './utils';

export interface YmUploadProps
  extends Omit<
    UploadProps,
    | 'style'
    | 'itemRender'
    | 'fileList'
    | 'defaultFileList'
    | 'onChange'
    | 'listType'
  > {
  style?: CSSProperties; //只对type drag生效,且是组件根部的div直接生效
  wrapperStyle?: CSSProperties; // 最外层根组件的样式
  value?: UploadFile[]; // 值
  defaultValue?: UploadFile[]; // 默认值
  onChange?(fileList: UploadFile[], file: UploadFile): void;
  maxSize?: number; // 最大尺寸，单位b
  cardWidth?: number;
  cardHeight?: number;
  acceptExt?: string; // 允许上传的后缀名称
  outMessage?: MessageInstance;
  listType?: ListItemType | UploadListType;
}

export function useYmUpload({
  listType: invokeListType = 'image-card',
  maxCount,
  onChange,
  value: invokeFileList,
  defaultValue: invokeDefaultFileList,
  children: selectText,
  className,
  wrapperStyle,
  maxSize = Infinity,
  beforeUpload,
  cardWidth,
  cardHeight,
  acceptExt,
  outMessage,
  ...props
}: YmUploadProps): UploadProps {
  const init = useRef(false);

  // 可以获取全局设置的size尺寸
  const cssStyle = useStyle({
    isOnlyOne: maxCount === 1,
    wrapperStyle,
    cardStyle: {
      width: cardWidth,
      height: cardHeight,
    },
  });

  const [fileList, setFileList] = useState<UploadFile[]>();
  useEffect(() => {
    if (init.current) {
      setFileList(invokeFileList);
    } else {
      setFileList(invokeFileList ?? invokeDefaultFileList);
    }
  }, [invokeFileList]);

  const listType = useMemo<UploadProps['listType']>(() => {
    if (invokeListType === 'image-card' || invokeListType === 'video-card') {
      return 'picture-card';
    } else if (invokeListType === 'info-list') {
      return 'text';
    } else {
      return props.type === 'drag' ? 'text' : invokeListType;
    }
  }, [invokeListType, props.type]);

  const fileLen = fileList?.length ?? 0;
  const disabled = fileLen >= (maxCount ?? Infinity);

  const children = useMemo<ReactNode>(() => {
    if (invokeListType === 'image-card' && disabled) {
      return null;
    }

    if (isValidElement(selectText)) {
      return selectText;
    }

    if (props.type === 'drag') {
      const text = selectText ? selectText : '将文件拖至此处或点击选择文件上传';
      return (
        <>
          <p className="ant-upload-drag-icon">
            <InboxOutlined />
          </p>
          <p className="ant-upload-text">{text}</p>
        </>
      );
    } else {
      const text = selectText ? selectText : '请选择';

      if (invokeListType === 'info-list') {
        return (
          <Button type="primary" icon={<UploadOutlined />} disabled={disabled}>
            {text}
          </Button>
        );
      }
      if (invokeListType === 'image-card' || invokeListType === 'video-card') {
        const icon =
          maxCount === 1 ? (
            <UploadOutlined style={{ fontSize: 24 }} />
          ) : (
            <PlusOutlined style={{ fontSize: 24 }} />
          );

        return (
          <div style={{ color: '#666' }}>
            {icon}
            <div>{text}</div>
          </div>
        );
      }
    }

    return null;
  }, [invokeListType, maxCount, disabled, selectText]);

  const itemRenderSzie = useMemo<{ width: number; height: number }>(() => {
    let tempWidth, tempHeight;
    if (cardWidth) {
      tempWidth = cardWidth;
      tempHeight = cardHeight ?? cardWidth;
    } else if (wrapperStyle?.width) {
      tempWidth = wrapperStyle?.width;
      tempHeight = wrapperStyle?.height;
      if (typeof tempWidth === 'string') {
        tempWidth = Number(tempWidth.split('px')[0]);
      }
      if (typeof tempHeight === 'string') {
        tempHeight = Number(tempHeight.split('px')[0]);
      } else if (!tempHeight) {
        tempHeight = tempWidth;
      }
    } else {
      tempWidth = tempHeight = 100;
    }
    return {
      width: tempWidth,
      height: tempHeight,
    };
  }, [wrapperStyle?.width, cardWidth, cardHeight]);
  //自定义上传列表项
  const itemRender = useCallback<NonNullable<UploadProps['itemRender']>>(
    (orginNode, file, fileList, actions) => {
      if (invokeListType === 'info-list') {
        // 列表形式
        return (
          <InfoItem
            itemRenderSzie={itemRenderSzie}
            file={file}
            fileList={fileList}
            {...actions}
          ></InfoItem>
        );
      } else if (invokeListType === 'image-card' || 'video-card') {
        // 图片/视频形式
        return (
          <CardItem
            file={file}
            fileList={fileList}
            itemRenderSzie={itemRenderSzie}
            {...actions}
            showActionText={Boolean(cardWidth && cardWidth >= 160)}
          ></CardItem>
        );
      } else {
        // 其他走默认
        return orginNode;
      }
    },
    [invokeListType, itemRenderSzie],
  );

  return {
    fileList,
    listType,
    maxCount,
    multiple: true, // 只是用来确定是否可以一次选择多个
    itemRender,
    beforeUpload(file, FileList) {
      if (file.size > maxSize) {
        outMessage?.error('选择文件内容过大');
        return Upload.LIST_IGNORE;
      }
      let allext = acceptExt;
      if (invokeListType === 'image-card') {
        allext ??= 'png,jpeg,jpg';
      }
      if (invokeListType === 'video-card') {
        allext ??= 'mp4';
      }
      if (allext) {
        const ext = file.name.split('.').pop();
        if (!ext || !allext.split(',').includes(ext)) {
          outMessage?.error('选择文件类型错误');
          return Upload.LIST_IGNORE; //此时列表中将不展示此文件
        }
      }

      return beforeUpload?.(file, FileList) ?? file;
    },
    previewFile: fileToBase64, //自定义文件预览逻辑
    onChange({ file, fileList: fl }) {
      if (file.status === 'uploading' && file.percent === 0) {
        if (file.percent === 0) {
          setFileList(fl);
          onChange?.(fl, file);
        }
      } else {
        setFileList(fl);
        onChange?.(fl, file);
      }
    },
    children,
    className: cssStyle.cx([cssStyle.styles.container, className]),
    ...props,
    disabled: props.disabled || disabled,
  };
}

export function YmUpload(props: YmUploadProps) {
  const [msg, contentHolder] = message.useMessage();
  const uploadProps = useYmUpload({ ...props, outMessage: msg });
  // 单张支持重新上传，多张不需要支持重新上传，用户自行删除即可
  return (
    <>
      <Upload {...uploadProps} />
      {contentHolder}
    </>
  );
}
